from uuid import UUID
from fastapi import UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional, List
from crud.document import personal_document as document_crud
from core.document.file_storage import delete_file
from schemas.document.personal_document import PersonalDocumentCreate, PersonalDocumentUpdate, PersonalDocumentResponse, DocumentSearchRequest, PaginatedDocumentResponse, DocumentStatistics
from core.document import file_storage
from log import log_info, log_error


async def upload_document(
    db: AsyncSession,
    file: UploadFile,
    document_data: PersonalDocumentCreate
) -> PersonalDocumentResponse:
    """上传文档"""
    try:
        log_info(f"开始上传文档: {file.filename}", module="core.personal_document")
        
        # 保存文件
        file_path, file_info = await file_storage.save_uploaded_file(file)
        
        # 如果没有提供标题，使用文件名作为标题
        if not document_data.title.strip():
            document_data.title = file.filename
        
        # 创建文档记录
        db_document = await document_crud.create_document(db, document_data, file_info)
        
        log_info(f"文档上传成功: {db_document.title} (ID: {db_document.id})", module="core.personal_document")
        return db_document
        
    except Exception as e:
        log_error(f"文档上传失败: {str(e)}", exc_info=True, module="core.personal_document")
        # 如果数据库操作失败，尝试删除已上传的文件
        if 'file_path' in locals():
            await file_storage.delete_file(file_path)
        raise


async def get_document_detail(db: AsyncSession, document_id: UUID) -> Optional[PersonalDocumentResponse]:
    """获取文档详情并更新访问记录"""
    try:
        log_info(f"获取文档详情: {document_id}", module="core.personal_document")
        
        # 获取文档
        document = await document_crud.get_document_by_id(db, document_id)
        if not document:
            return None
        
        # 更新查看次数和最后访问时间
        await document_crud.update_view_count(db, document_id)
        
        # 重新获取更新后的文档信息
        updated_document = await document_crud.get_document_by_id(db, document_id)
        
        log_info(f"文档详情获取成功: {document.title}", module="core.personal_document")
        return updated_document
        
    except Exception as e:
        log_error(f"获取文档详情失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def update_document(
    db: AsyncSession,
    document_id: UUID,
    document_update: PersonalDocumentUpdate
) -> Optional[PersonalDocumentResponse]:
    """更新文档信息"""
    try:
        log_info(f"更新文档: {document_id}", module="core.personal_document")
        
        # 检查文档是否存在
        existing_document = await document_crud.get_document_by_id(db, document_id)
        if not existing_document:
            log_error(f"文档不存在: {document_id}", module="core.personal_document")
            return None
        
        # 更新文档
        updated_document = await document_crud.update_document(db, document_id, document_update)
        
        if updated_document:
            log_info(f"文档更新成功: {updated_document.title}", module="core.personal_document")
        
        return updated_document
        
    except Exception as e:
        log_error(f"更新文档失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def delete_document(db: AsyncSession, document_id: UUID) -> bool:
    """删除文档及其文件"""
    try:
        log_info(f"删除文档: {document_id}", module="core.personal_document")
        
        # 获取文档信息
        document = await document_crud.get_document_by_id(db, document_id)
        if not document:
            log_error(f"文档不存在: {document_id}", module="core.personal_document")
            return False
        
        # 删除数据库记录
        success = await document_crud.delete_document(db, document_id)
        
        if success:
            # 删除文件
            await file_storage.delete_file(document.file_path)
            log_info(f"文档删除成功: {document.title}", module="core.personal_document")
        
        return success
        
    except Exception as e:
        log_error(f"删除文档失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def search_documents(
    db: AsyncSession,
    search_request: DocumentSearchRequest
) -> PaginatedDocumentResponse:
    """搜索文档"""
    try:
        log_info(f"搜索文档: {search_request.search}", module="core.personal_document")
        
        # 计算偏移量
        offset = (search_request.page - 1) * search_request.size
        
        # 执行搜索
        documents, total = await document_crud.get_documents_paginated(
            db=db,
            category_id=search_request.category_id,
            search=search_request.search,
            tag_names=search_request.tags,
            is_favorite=search_request.is_favorite,
            is_pinned=search_request.is_pinned,
            sort_by=search_request.sort_by,
            sort_order=search_request.sort_order,
            offset=offset,
            limit=search_request.size
        )
        
        # 计算总页数
        pages = (total + search_request.size - 1) // search_request.size
        
        # 构建响应
        response = PaginatedDocumentResponse(
            items=[PersonalDocumentResponse.model_validate(doc) for doc in documents],
            total=total,
            page=search_request.page,
            size=search_request.size,
            pages=pages
        )
        
        log_info(f"搜索完成: 找到 {total} 个文档", module="core.personal_document")
        return response
        
    except Exception as e:
        log_error(f"搜索文档失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def toggle_document_favorite(db: AsyncSession, document_id: UUID) -> Optional[PersonalDocumentResponse]:
    """切换文档收藏状态"""
    try:
        log_info(f"切换文档收藏状态: {document_id}", module="core.personal_document")
        
        updated_document = await document_crud.toggle_favorite(db, document_id)
        
        if updated_document:
            status = "收藏" if updated_document.is_favorite else "取消收藏"
            log_info(f"文档{status}成功: {updated_document.title}", module="core.personal_document")
        
        return updated_document
        
    except Exception as e:
        log_error(f"切换收藏状态失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def toggle_document_pin(db: AsyncSession, document_id: UUID) -> Optional[PersonalDocumentResponse]:
    """切换文档置顶状态"""
    try:
        log_info(f"切换文档置顶状态: {document_id}", module="core.personal_document")
        
        updated_document = await document_crud.toggle_pin(db, document_id)
        
        if updated_document:
            status = "置顶" if updated_document.is_pinned else "取消置顶"
            log_info(f"文档{status}成功: {updated_document.title}", module="core.personal_document")
        
        return updated_document
        
    except Exception as e:
        log_error(f"切换置顶状态失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def batch_delete_documents(db: AsyncSession, document_ids: List[UUID]) -> int:
    """批量删除文档"""
    try:
        log_info(f"批量删除文档: {len(document_ids)} 个", module="core.personal_document")
        
        # 获取要删除的文档信息
        documents_to_delete = []
        for document_id in document_ids:
            document = await document_crud.get_document_by_id(db, document_id)
            if document:
                documents_to_delete.append(document)
        
        # 删除数据库记录
        deleted_count = await document_crud.batch_delete_documents(db, document_ids)
        
        # 删除文件
        for document in documents_to_delete:
            await delete_file(document.file_path)
        
        log_info(f"批量删除完成: {deleted_count} 个文档", module="core.personal_document")
        return deleted_count
        
    except Exception as e:
        log_error(f"批量删除失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def batch_move_documents(db: AsyncSession, document_ids: List[UUID], category_id: Optional[UUID]) -> int:
    """批量移动文档到指定分类"""
    try:
        log_info(f"批量移动文档: {len(document_ids)} 个到分类 {category_id}", module="core.personal_document")
        
        # 如果指定了分类，验证分类是否存在
        if category_id:
            from crud.document import document_category as category_crud
            category = await category_crud.get_category_by_id(db, category_id)
            if not category:
                raise ValueError("目标分类不存在")
        
        # 执行批量移动
        moved_count = await document_crud.batch_move_documents(db, document_ids, category_id)
        
        log_info(f"批量移动完成: {moved_count} 个文档", module="core.personal_document")
        return moved_count
        
    except Exception as e:
        log_error(f"批量移动失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def get_document_statistics(db: AsyncSession) -> DocumentStatistics:
    """获取文档统计信息"""
    try:
        log_info("获取文档统计信息", module="core.personal_document")
        
        # 获取基础统计
        basic_stats = await document_crud.get_documents_statistics(db)
        
        # 直接使用SQL聚合函数计算总文件大小
        total_size = await document_crud.get_total_file_size(db)
        
        # 手动获取分类统计
        by_category = {}
        try:
            from crud.document.document_category import get_categories_with_document_count
            categories_result = await get_categories_with_document_count(db)
            
            # 输出调试信息
            log_info(f"分类统计原始数据: {categories_result}", module="core.personal_document")
            
            # 安全处理分类统计数据
            for item in categories_result:
                if hasattr(item, "_mapping"):
                    # 如果是Row对象
                    category = item[0] if len(item) > 0 else None
                    count = item[1] if len(item) > 1 else 0
                    if category and hasattr(category, "name") and count > 0:
                        by_category[category.name] = count
                elif isinstance(item, tuple) and len(item) >= 2:
                    # 如果是元组
                    category, count = item[0], item[1]
                    if hasattr(category, "name") and count > 0:
                        by_category[category.name] = count
            
            log_info(f"分类统计处理完成: {len(by_category)} 个分类有文档", module="core.personal_document")
        except Exception as e:
            log_error(f"处理分类统计数据失败: {str(e)}", exc_info=True, module="core.personal_document")
            by_category = {}  # 出错时使用空字典
        
        # 创建统计对象
        statistics = DocumentStatistics(
            total=basic_stats["total"],
            favorites=basic_stats["favorites"],
            by_type=basic_stats["by_type"],
            by_category=by_category,
            total_size=total_size
        )
        
        log_info(f"统计信息获取完成: 总计 {statistics.total} 个文档", module="core.personal_document")
        return statistics
        
    except Exception as e:
        log_error(f"获取统计信息失败: {str(e)}", exc_info=True, module="core.personal_document")
        # 在出错时返回空统计信息而不是抛出异常
        return DocumentStatistics(
            total=0,
            favorites=0,
            by_type={},
            by_category={},
            total_size=0
        )


async def get_favorite_documents(db: AsyncSession, limit: int = 10) -> List[PersonalDocumentResponse]:
    """获取收藏的文档"""
    try:
        log_info(f"获取收藏文档，限制 {limit} 个", module="core.personal_document")
        
        documents = await document_crud.get_favorite_documents(db, limit)
        
        log_info(f"获取到 {len(documents)} 个收藏文档", module="core.personal_document")
        return documents
        
    except Exception as e:
        log_error(f"获取收藏文档失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise


async def get_recent_documents(db: AsyncSession, limit: int = 10) -> List[PersonalDocumentResponse]:
    """获取最近访问的文档"""
    try:
        log_info(f"获取最近访问文档，限制 {limit} 个", module="core.personal_document")
        
        documents = await document_crud.get_recent_documents(db, limit)
        
        log_info(f"获取到 {len(documents)} 个最近访问文档", module="core.personal_document")
        return documents
        
    except Exception as e:
        log_error(f"获取最近访问文档失败: {str(e)}", exc_info=True, module="core.personal_document")
        raise
